package com.incar.chuxing.utils.ble;


import com.incar.chuxing.utils.Logger;

import java.util.Arrays;

/**
 * Created by michaelpi on 2018/1/17.
 */

public class YunCheParseUtils {
    private static final YunCheParseUtils instance = new YunCheParseUtils();

    public static YunCheParseUtils getInstance() {
        return instance;
    }

    private YunCheParseUtils() {
    }

    static {
        System.loadLibrary("AES");
        System.loadLibrary("track_fun_AES");
    }

    private native byte[] Key1Decryption(byte[] date);

    private native byte[] Key1Encryption(byte[] date);

    private native byte[] Key2Encryption(byte[] date);

    /**
     * 握手指令
     */
    byte[] createPswHandShakeCmd() {
        byte[] cmdBytes = {(byte) 0xBD, 0x11, (byte) 0xB1, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00};
        return getSummedCmd(cmdBytes);
    }

    /**
     * 唤醒指令
     */
    byte[] createWakeCmd() {
        byte[] cmdBytes = {(byte) 0xBD, 0x11, (byte) 0xA1, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00};
        return getSummedCmd(cmdBytes);
    }

    /**
     * 申请验证密码指令
     */
    byte[] createApplyForVerifyPswCmd() {
        byte[] cmdBytes = {(byte) 0xBD, 0x11, (byte) 0xB2, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00};
        return getSummedCmd(cmdBytes);
    }

    byte[] createVerifyPswCmd(String psw) {
        byte[] rawPswBytes = new byte[psw.length()];
        int i = 0;
        while (i < psw.length()) {
            rawPswBytes[i] = Byte.parseByte(psw.substring(i, i + 1));
            i += 1;
        }
        if (psw.length() == 6) {
            byte[] rawCmd = {(byte) 0xBD, 0x11, (byte) 0xB4, 0x76, 0x72, 0x66, 0x70, 0x77, 0x64, 0x2D, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
            //把获得密码插入进数组
            System.arraycopy(rawPswBytes, 0, rawCmd, 11, rawPswBytes.length);//源数组，源数组要复制的起始位置，目的数组，目的数组放置的起始位置，复制的长度
            //数据内容AES2加密
            return aes2Encrypt(rawCmd);
        } else if (psw.length() == 7) {
            byte[] rawCmd = {(byte) 0xBD, 0x11, (byte) 0xB4, 0x76, 0x72, 0x66, 0x70, 0x77, 0x64, 0x2D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
            //把获得密码插入进数组
            System.arraycopy(rawPswBytes, 0, rawCmd, 11, rawPswBytes.length);//源数组，源数组要复制的起始位置，目的数组，目的数组放置的起始位置，复制的长度
            //数据内容AES2加密
            return aes2Encrypt(rawCmd);
        } else if (psw.length() == 8) {
            byte[] rawCmd = {(byte) 0xBD, 0x11, (byte) 0xB4, 0x76, 0x72, 0x66, 0x70, 0x77, 0x64, 0x2D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
            //把获得密码插入进数组
            System.arraycopy(rawPswBytes, 0, rawCmd, 11, rawPswBytes.length);//源数组，源数组要复制的起始位置，目的数组，目的数组放置的起始位置，复制的长度
            //数据内容AES2加密
            return aes2Encrypt(rawCmd);
        } else {
            byte[] rawCmd = {(byte) 0xBD, 0x11, (byte) 0xB4, 0x76, 0x72, 0x66, 0x70, 0x77, 0x64, 0x2D, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
            //把获得密码插入进数组
            System.arraycopy(rawPswBytes, 0, rawCmd, 11, rawPswBytes.length);//源数组，源数组要复制的起始位置，目的数组，目的数组放置的起始位置，复制的长度
            //数据内容AES2加密
            return aes2Encrypt(rawCmd);
        }
    }


    /**
     * 申请控制/申请获取数据指令
     */
    byte[] createApplyForControlCmd() {
        byte[] cmdBytes = {(byte) 0xBD, 0x11, (byte) 0xA2, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00};
        return getSummedCmd(cmdBytes);
    }

    /**
     * 控制指令
     */
    byte[] createControlCmd(BleConstants.ControlType controlType) {

        byte[] cmdBytes;
        if (controlType == BleConstants.ControlType.OPEN_DOOR) {
            cmdBytes = new byte[]{(byte) 0xBD, 0x11, (byte) 0xA5, 0x5A, 0x44, 0x2D, 0x42, 0x54, 0x2D, 0x43, 0x6D, 0x64, 0x2D, 0x55, 0x6E, 0x4C, 0x6F, 0x63, 0x6B, 0x00};
        } else {
            cmdBytes = new byte[]{(byte) 0xBD, 0x11, (byte) 0xA4, 0x5A, 0x44, 0x2D, 0x42, 0x54, 0x2D, 0x43, 0x6D, 0x64, 0x2D, 0x4C, 0x6F, 0x63, 0x6B, 0x21, 0x21, 0x00};
        }
        //数据内容AES2加密
        return aes2Encrypt(cmdBytes);

    }


    /**
     * 控制指令
     */
    byte[] createStatusCmd() {
        byte[] cmdBytes;
        cmdBytes = new byte[]{(byte) 0xBD, 0x11, (byte) 0xA7, 0x5A, 0x44, 0x2D, 0x42, 0x54, 0x2D, 0x47, 0x65, 0x74, 0x2D, 0x49, 0x6E, 0x66, 0x6F, 0x30, 0x31, 0x00};
        //数据内容AES1加密
        return aes1Encrypt(cmdBytes);

    }


    /**
     * AES1解密
     *
     * @param data 要解密的完整响应，20字节
     * @return 解密后响应，20字节
     */
    byte[] aes1Decrypt(byte[] data) {
        Logger.i("bleinfo-Helper", "解密开始");
        byte[] encryptedBytes = new byte[16];
        System.arraycopy(data, 3, encryptedBytes, 0, 16);
        Logger.i("bleinfo-Helper", "解密开始1");
        System.arraycopy(Key1Decryption(encryptedBytes), 0, data, 3, 16);
        Logger.i("bleinfo-Helper", "解密开始2");
        return data;
    }

    /**
     * AES1加密
     *
     * @param data 要加密的完整指令，20字节
     * @return 加密后的指令，20字节
     */
    public byte[] aes1Encrypt(byte[] data) {
        byte[] encryptedBytes = new byte[16];
        //从未加密数组，取出数据部分
        System.arraycopy(data, 3, encryptedBytes, 0, 16);
        //把机密后的数据部分，放回传进来的数组中
        System.arraycopy(Key1Encryption(encryptedBytes), 0, data, 3, 16);
        return getSummedCmd(data);
    }


    /**
     * AES2加密
     *
     * @param data 要加密的完整指令，20字节
     * @return 加密后的指令，20字节
     */
    byte[] aes2Encrypt(byte[] data) {
        byte[] unDecryptedBytes = new byte[16];
        //从未加密数组，取出数据部分
        System.arraycopy(data, 3, unDecryptedBytes, 0, 16);//源数组，源数组要复制的起始位置，目的数组，目的数组放置的起始位置，复制的长度
        //把机密后的数据部分，放回传进来的数组中
        System.arraycopy(Key2Encryption(unDecryptedBytes), 0, data, 3, 16);
        return getSummedCmd(data);
    }


    /**
     * 填充校验和
     *
     * @param cmdBytes 20位未添加校验和的指令
     * @return 添加了校验和的20位指令
     */
    private byte[] getSummedCmd(byte[] cmdBytes) {
        int sum = 0;
        for (int i = 0; i <= 18; i++) {
            sum += cmdBytes[i];
        }
        //填写校验和
        cmdBytes[19] = (byte) (~sum);
        return cmdBytes;
    }


    int[] parseStatus(byte[] data) {
        //取出字节的位，1:true  0:false
        int[] statusArray = new int[8];
        for (int i = 0; i < 8; i++) {
            statusArray[i] = ((data[3] & (1 << i)) != 0 ? 1 : 0);
        }
        int[] status = new int[16];
        status[BleConstants.CarStatus.FL_DOOR] = statusArray[1];
        status[BleConstants.CarStatus.FR_DOOR] = statusArray[2];
        status[BleConstants.CarStatus.RL_DOOR] = statusArray[3];
        status[BleConstants.CarStatus.RR_DOOR] = statusArray[4];
        status[BleConstants.CarStatus.TRUNK] = statusArray[5];
        status[BleConstants.CarStatus.ENGINE] = statusArray[0];
        status[BleConstants.CarStatus.MILEAGE] = (data[6] & 0xff) * 65536 + (data[5] & 0xff) * 256 + (data[4] & 0xff);
        Logger.i("bleinfo", "Y-carStatus " + Arrays.toString(status));
        return status;
    }
}
